#!/usr/bin/env python

# preferences-dialog - Preferences editing tool for Entertainer media center.
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import os
import sys
import shutil
import string
import tarfile
import ConfigParser
from ConfigParser import ParsingError

from utils.theme import Theme

from backend.core.message import Message
from backend.core.message_bus_proxy import MessageBusProxy
from backend.core.message_type_priority import MessageType

try:
 	import pygtk
  	pygtk.require("2.4")
except:
  	pass
try:
	import gtk
  	import gtk.glade
except:
	sys.exit(1)
	
class PreferencesDialog:
    """This is a preferences editing tool for Entertainer media center."""
    
    # Configuration file location
    CONFIG_FILE = os.path.expanduser('~/.entertainer/preferences.conf')

    def __init__(self, stand_alone):
        """
        Initialize Preferenced dialog
        @param stand_alone: Is this dialog stand alone process or part of frontend
        """
        self.STAND_ALONE = stand_alone # Is this dialog running as a stand alone process
        self.themes = []
        self.config = ConfigParser.ConfigParser()
        try:
            self.config.readfp(open(self.CONFIG_FILE))
        except ParsingError:
            print "Syntax error in configuration file: " + self.CONFIG_FILE
            print "Execution aborted!"
            sys.exit(1)
        except IOError:
            print "Configuration file is missing: " + self.CONFIG_FILE
            print "Execution aborted!"
            #FIXME: We should create a default preferences file if file is missing
            sys.exit(1)
        except:
            print "Unknown error occured when preferences file was loaded!"
            print "Execution aborted!"
            sys.exit(1)
            
        # Load glade UI
        self.gladefile = "utils/glade/entertainer-preferences.glade"
        self.widgets = gtk.glade.XML(self.gladefile)
        
        # Get preferences dialog and bind signal callbacks
        self.pref_dialog = self.widgets.get_widget("PreferencesDialog")
        if (self.pref_dialog):
            callback_dic = { "on_close_button_clicked" : self.on_close_button_clicked,
	                         "on_PreferencesDialog_delete_event" : self.on_dialog_closed,
	                         "on_theme_list_cursor_changed" : self.on_theme_list_cursor_changed,
	                         "on_effect_checkbox_toggled" : self.on_effect_checkbox_toggled,
	                         "on_effect_combobox_changed" : self.on_effect_combobox_changed,
	                         "on_add_button_clicked" : self.on_add_button_clicked,
	                         "on_remove_button_clicked" : self.on_remove_button_clicked }
        self.widgets.signal_autoconnect(callback_dic)
        
        # Initilize dialog widgets with correct values and show dialog
        self.init_dialog_values_from_configure_file()
        #self.pref_dialog.resize(500,400)
        self.pref_dialog.show()
    
    def load_themes(self):
        """Load themes"""
        themes = os.listdir(os.path.expanduser('~/.entertainer/themes'))
        for element in themes:
            theme = os.path.join(os.path.expanduser('~/.entertainer/themes'), element)
            if os.path.isdir(theme):
                try:
                    self.themes.append(Theme(theme))
                except:
                    pass # Folder is not a Theme folder. Move on

    def on_add_button_clicked(self, widget):
        """Add theme button clicked"""
        themelist = self.widgets.get_widget("theme_list")
        model = themelist.get_model()
        # Open "Select folder" dialog
        dialog =  gtk.FileChooserDialog("Select theme package file", 
                                        None,
                                        gtk.FILE_CHOOSER_ACTION_OPEN,
                                        (gtk.STOCK_CANCEL,
                                         gtk.RESPONSE_CANCEL,
                                         gtk.STOCK_OPEN,
                                         gtk.RESPONSE_OK), 
                                         None)
        filter = gtk.FileFilter()
        filter.set_name("Theme package (tar.gz)")
        filter.add_pattern("*.tar.gz")
        dialog.add_filter(filter)
        status = dialog.run()
        
        # If theme was selected with file chooser
        if(status == gtk.RESPONSE_OK):
            package = dialog.get_filename()
            try:
                tar = tarfile.open(package, 'r:gz') # Open tar.gz package
            except:
                error = gtk.MessageDialog(None, 
                                          gtk.DIALOG_MODAL, 
                                          gtk.MESSAGE_ERROR, 
                                          gtk.BUTTONS_OK, 
                                          "Invalid theme file!")
                error.run()
                error.destroy()
                dialog.destroy()
                return
                
            # Make sure that package contains configuration file (is theme)
            content = tar.getnames()
            themedir = None
            is_theme = False
            for element in content:
                if element[-10:] == "theme.conf":
                    themedir = element[:-11]
                    is_theme = True
                    
            # Install theme        
            if is_theme:
                tar.extractall(os.path.expanduser('~/.entertainer/themes'))
                new_theme = Theme(os.path.join(os.path.expanduser('~/.entertainer/themes'), themedir))
                model.insert(len(model), [new_theme.getName()])
            else:
                error = gtk.MessageDialog(None, 
                                          gtk.DIALOG_MODAL, 
                                          gtk.MESSAGE_ERROR, 
                                          gtk.BUTTONS_OK, 
                                          "Invalid theme file!")
                error.run()
                error.destroy()
                
        dialog.destroy()
        
    def on_remove_button_clicked(self, widget):
        """Remove theme button clicked"""
        # Get currently selected theme
        themelist = self.widgets.get_widget("theme_list")
        model = themelist.get_model()
        selection = themelist.get_selection().get_selected()
        name = model.get_value(selection[1], 0)
        
        confirm = gtk.MessageDialog(None, 
                                    gtk.DIALOG_MODAL, 
                                    gtk.MESSAGE_QUESTION, 
                                    gtk.BUTTONS_YES_NO, 
                                    "Are you sure you want to delete\ntheme: "+ name)
        status = confirm.run()
        confirm.destroy()
        if(status == gtk.RESPONSE_YES):
            #FIXME: Do we need to remove this from self.themes
            themedir = os.path.join(os.path.expanduser('~/.entertainer/themes'), name)
            shutil.rmtree(themedir)
            model.remove(selection[1])
            themelist.set_cursor(0)
        
    def on_theme_list_cursor_changed(self, widget):
        """Executed when theme is changed in theme list. Update preview."""
        # Get currently selected theme
        themelist = self.widgets.get_widget("theme_list")
        model = themelist.get_model()
        selection = themelist.get_selection().get_selected()
        name = model.get_value(selection[1], 0)
        themedir = os.path.join(os.path.expanduser('~/.entertainer/themes'), name)
        theme = Theme(themedir)
        
        # Update preview
        image = self.widgets.get_widget("theme_image")
        image.set_from_file(os.path.join(themedir, "thumbnail.png"))
        name = self.widgets.get_widget("name_label")
        name.set_text(theme.getName())
        author = self.widgets.get_widget("author_label")
        author.set_text(theme.getAuthor())
        licence = self.widgets.get_widget("licence_label")
        licence.set_text(theme.getLicence())
        copyright = self.widgets.get_widget("copyright_label")
        copyright.set_text(theme.getCopyright())
        comment = self.widgets.get_widget("comment_label")
        comment.set_text(theme.getComment())
        
        self.config.set("General","theme", name.get_text())
        cfg_file = file(self.CONFIG_FILE, 'w')
        self.config.write(cfg_file)
    
    def on_effect_checkbox_toggled(self, widget):
        """Effect checkbox toggled"""
        combobox = self.widgets.get_widget("effect_combobox")
        combobox.set_sensitive(widget.get_active())
        self.config.set("General","show_effects", widget.get_active())
        cfg_file = file(self.CONFIG_FILE, 'w')
        self.config.write(cfg_file)
        
    def on_effect_combobox_changed(self, widget):
        """User changed effect for screen transitions"""
        self.config.set("General","transition_effect", widget.get_active_text())
        cfg_file = file(self.CONFIG_FILE, 'w')
        self.config.write(cfg_file)
        
    def on_dialog_closed(self, widget, after):
        """Callback function for dialog's close button"""
        try:
            proxy = MessageBusProxy(client_name = "Preferences GUI")
            proxy.connectToMessageBus()
            proxy.sendMessage(Message(MessageType.PREFERENCES_CFG_UPDATED))
            proxy.disconnectFromMessageBus()
        except:
            pass # This means that backend is not running. Doesn't matter
        
        if(self.STAND_ALONE):
            self.pref_dialog.hide()
            self.pref_dialog.destroy()
            gtk.main_quit()
        else:
            self.pref_dialog.hide()
            self.pref_dialog.destroy()

    def on_close_button_clicked(self, widget):
        """Callback function for dialog's close button"""
        try:
            proxy = MessageBusProxy(client_name = "Preferences GUI")
            proxy.connectToMessageBus()
            proxy.sendMessage(Message(MessageType.PREFERENCES_CFG_UPDATED))
            proxy.disconnectFromMessageBus()
        except:
            pass # This means that backend is not running. Doesn't matter
        
        if(self.STAND_ALONE):
            self.pref_dialog.hide()
            self.pref_dialog.destroy()
            gtk.main_quit()
        else:
            self.pref_dialog.hide()
            self.pref_dialog.destroy()

    def init_dialog_values_from_configure_file(self):
        """Read configure file and set dialog widget values with read values."""
        self.load_themes()
        current_theme = self.config.get("General", "theme") # Error threat

        themelist_widget = self.widgets.get_widget("theme_list")
        model = gtk.ListStore(str)
        
        cell_renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Themes", cell_renderer, text=0)
        themelist_widget.append_column(column)

        # Fill model with installed themes
        for i in range(len(self.themes)):
            model.insert(i, [self.themes[i].getName()])

        themelist_widget.set_model(model)
        
        # Set current theme selected in theme list
        #FIXME: There must be a more elegant way to do this
        try:
            iter = model.get_iter_first()
            unselected = True
            index_counter = 0
            while(unselected):
                name = model.get_value(iter, 0)
                if name == current_theme:
                    unselected = False
                    themelist_widget.set_cursor(index_counter)
                iter = model.iter_next(iter)
                index_counter += 1
        except:
            pass # Error in configfile
        
        # Checkboxes
        effect_checkbox = self.widgets.get_widget("effect_checkbox")
        effect_combobox = self.widgets.get_widget("effect_combobox")
        show_effects = self.config.getboolean("General", "show_effects") # Error threat
        effect = self.config.get("General", "transition_effect") # Error threat
        if show_effects:
            effect_checkbox.set_active(True)
            effect_combobox.set_sensitive(True)
        else:
            effect_checkbox.set_active(False)
            effect_combobox.set_sensitive(False)
            
        # Set Effect Combobox value (Text values are set in glade file)
        if effect == "No effect":
            effect_combobox.set_active(0)
        if effect == "Crossfade":
            effect_combobox.set_active(1)
        if effect == "Zoom and fade":
            effect_combobox.set_active(2)
        if effect == "Slide":
            effect_combobox.set_active(3)
        if effect == "Slide and fade":
            effect_combobox.set_active(4)
